#ifndef _GPIO_DRIVER_H
#define _GPIO_DRIVER_H

#include <stdbool.h>
#include "core/drv.h"

typedef device_t gpio_device_t;
typedef void (*gpio_isr_cb)(gpio_device_t *dev, void *args);



#define GPIO_PIN_ENUM_MAX GPIO_IO_PIN_MAX
#define GPIO_PIN_ENUM_MIN GPIO_IO_PIN_MIN
#define GPIO_PIN_ENUM_ENTRY(n) GPIO_DEVICE_NUM_##n,

typedef enum gpio_pin_map {
    GPIO_PIN_ENUM_ENTRY(NONE)
    GPIO_PIN_ENUM_ENTRY(0)
    GPIO_PIN_ENUM_ENTRY(1)
    GPIO_PIN_ENUM_ENTRY(2)
    GPIO_PIN_ENUM_ENTRY(3)
    GPIO_PIN_ENUM_ENTRY(4)
    GPIO_PIN_ENUM_ENTRY(5)
    GPIO_PIN_ENUM_ENTRY(6)
    GPIO_PIN_ENUM_ENTRY(7)
    GPIO_PIN_ENUM_ENTRY(8)
    GPIO_PIN_ENUM_ENTRY(9)
    GPIO_PIN_ENUM_ENTRY(10)
    GPIO_PIN_ENUM_ENTRY(11)
    GPIO_PIN_ENUM_ENTRY(12)
    GPIO_DEVICE_NUM_MIN = GPIO_DEVICE_NUM_NONE,
    GPIO_DEVICE_NUM_MAX = GPIO_DEVICE_NUM_12,
} gpio_device_pin_t;



typedef enum gpio_ctrl_cmd{
    GPIO_CTRL_CMD_NONE,
    GPIO_CTRL_CMD_SET_LEVEL,
    GPIO_CTRL_CMD_GET_LEVEL,
    GPIO_CTRL_CMD_INTR_ENABLE,
    GPIO_CTRL_CMD_INTR_DISABLE,
    GPIO_CTRL_CMD_SET_INTR_MODE,
    GPIO_CTRL_CMD_ISRCB_ADD,
    GPIO_CTRL_CMD_ISRCB_REMOVE,
    GPIO_CTRL_CMD_SET_LOWPOWER_ENTER,
    GPIO_CTRL_CMD_SET_LOWPOWER_EXIT,
}gpio_ctrl_cmd_t;

typedef enum gpio_device_int_type{
    GPIO_INTR_DISABLE = 0,     /*!< Disable GPIO interrupt                             */
    GPIO_INTR_POSEDGE = 1,     /*!< GPIO interrupt type : rising edge                  */
    GPIO_INTR_NEGEDGE = 2,     /*!< GPIO interrupt type : falling edge                 */
    GPIO_INTR_ANYEDGE = 3,     /*!< GPIO interrupt type : both rising and falling edge */
    GPIO_INTR_LOW_LEVEL = 4,   /*!< GPIO interrupt type : input low level trigger      */
    GPIO_INTR_HIGH_LEVEL = 5,  /*!< GPIO interrupt type : input high level trigger     */
    GPIO_INTR_MAX,
} gpio_device_intr_type_t;

typedef enum gpio_device_mode{
    GPIO_DEVICE_MODE_DISABLE = 0x00,
    GPIO_DEVICE_MODE_INPUT,
    GPIO_DEVICE_MODE_OUTPUT,
    GPIO_DEVICE_MODE_OUTPUT_OD,
    GPIO_DEVICE_MODE_INPUT_OD,
}gpio_device_mode_t;

typedef enum gpio_pulldown{
    GPIO_PULLDOWN_DISABLE = 0x00,
    GPIO_PULLDOWN_ENABLE = 0x01,
}gpio_device_pulldown_t;

typedef enum gpio_pullup{
    GPIO_PULLUP_DISABLE = 0x00,
    GPIO_PULLUP_ENABLE = 0x01,
}gpio_device_pullup_t;

typedef enum gpio_pin_level{
    GPIO_PIN_LEVEL_NONE,
    GPIO_PIN_LEVEL_LOW,
    GPIO_PIN_LEVEL_HIGH,
}gpio_device_pin_level_t;



typedef struct gpio_device_config{
    gpio_device_mode_t mode;               /*!< GPIO mode: set input/output mode                     */
    gpio_device_pullup_t pull_up_en;       /*!< GPIO pull-up                                         */
    gpio_device_pulldown_t pull_down_en;   /*!< GPIO pull-down                                       */
    gpio_device_intr_type_t intr_type;      /*!< GPIO interrupt type                                  */
}gpio_device_config_t;

typedef struct gpio_private_context_t{
    void *args;
    gpio_isr_cb isr_cb;
    gpio_device_pin_t gpio_pin;
    gpio_device_config_t gpio_cfg;
    bool open_status;
    bool irq_enable_status;
    struct gpio_private_context_t *next;
    gpio_device_t *dev;
}gpio_private_context_t;




typedef struct gpio_hal_driver_ops{
    int (*hal_gpio_init)(gpio_device_pin_t pin, gpio_device_config_t *cfg);
    int (*hal_gpio_deinit)(gpio_device_pin_t pin);
    int (*hal_gpio_get_level)(gpio_device_pin_t pin);
    int (*hal_gpio_set_level)(gpio_device_pin_t pin, gpio_device_pin_level_t level);
    int (*hal_gpio_intr_enable)(gpio_device_pin_t pin);
    int (*hal_gpio_intr_disable)(gpio_device_pin_t pin);
    int (*hal_gpio_set_intr_type)(gpio_device_pin_t pin, gpio_device_intr_type_t type);
    int (*hal_gpio_set_lowpower_enter)(gpio_device_pin_t pin);
    int (*hal_gpio_set_lowpower_exit)(gpio_device_pin_t pin);
}gpio_hal_driver_ops_t;


typedef struct gpio_driver_ops{
    // int (*gpio_init)(device_t *dev, gpio_device_config_t *cfg);
    // int (*gpio_deinit)(device_t *dev);
    int (*gpio_get_level)(gpio_device_t *dev);
    int (*gpio_set_level)(gpio_device_t *dev, gpio_device_pin_level_t level);
    int (*gpio_intr_enable)(gpio_device_t *dev);
    int (*gpio_intr_disable)(gpio_device_t *dev);
    int (*gpio_set_intr_type)(gpio_device_t *dev, gpio_device_intr_type_t type);
    int (*gpio_isr_cb_add)(gpio_device_t *dev, gpio_isr_cb isr_cb, void *args);
    int (*gpio_isr_cb_remove)(gpio_device_t *dev);
    int (*gpio_set_lowpower_enter)(gpio_device_t *dev);
    int (*gpio_set_lowpower_exit)(gpio_device_t *dev);
}gpio_driver_ops_t;

EXTERN DEVICE_PUBLIC(driver_t) gpio_device_driver;
EXTERN DEVICE_PUBLIC(void) gpio_driver_isr_handler(gpio_device_pin_t gpio_pin);

#endif

